#include "Rtsp_Decoder.h"

#include <iostream>
#include <stdexcept>

Rtsp_Decoder::Rtsp_Decoder()
{
    avformat_network_init();
    
}

Rtsp_Decoder::~Rtsp_Decoder()
{
    close();
}

bool Rtsp_Decoder::open(const std::string& url) {
    AVDictionary* options = nullptr;
    av_dict_set(&options, "rtsp_transport", "tcp", 0); // 使用TCP传输
    // 打开输入流并查找流信息
    int ret = avformat_open_input(&formatContext, url.c_str(), nullptr, nullptr);
    if (ret < 0) {
        qDebug() << "Could not open source file:" << url.c_str();
        return false;
    }

    // 查找流信息
    ret = avformat_find_stream_info(formatContext, nullptr);
    if (ret < 0) {
        qDebug() << "Could not find stream information";
        return false;
    }

    // 打印流信息
    std::cout << "打印相关信息\n";
    av_dump_format(formatContext, 0, url.c_str(), 0);

    // 查找视频流
    videoStream = nullptr;
    for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = formatContext->streams[i];
            break;
        }
    }

    if (!videoStream) {
        qDebug() << "Could not find video stream";
        return false;
    }

    // 查找并打开解码器
    AVCodec *codec = avcodec_find_decoder(videoStream->codecpar->codec_id);
    if (!codec) {
        qDebug() << "Codec not found";
        return false;
    }

    codecContext = avcodec_alloc_context3(codec);
    if (!codecContext) {
        qDebug() << "Could not allocate video codec context";
        return false;
    }

    ret = avcodec_parameters_to_context(codecContext, videoStream->codecpar);
    if (ret < 0) {
        qDebug() << "Could not copy codec parameters to codec context";
        return false;
    }

    ret = avcodec_open2(codecContext, codec, nullptr);
    if (ret < 0) {
        qDebug() << "Could not open codec";
        return false;
    }

    // 初始化图像转换上下文
    swsContext = sws_getContext(
        codecContext->width,
        codecContext->height,
        codecContext->pix_fmt,
        codecContext->width,
        codecContext->height,
        AV_PIX_FMT_RGB24,
        SWS_BILINEAR,
        nullptr,
        nullptr,
        nullptr
    );

    return true;
}
void Rtsp_Decoder::close() {
    if (formatContext) {
        avformat_close_input(&formatContext);
    }
    if (codecContext) {
        avcodec_free_context(&codecContext);
    }
    if (swsContext) {
        sws_freeContext(swsContext);
    }
}

void Rtsp_Decoder::decode() {
    AVPacket packet;
    av_init_packet(&packet);

    while (av_read_frame(formatContext, &packet) >= 0) {
        if (packet.stream_index == videoStream->index) {
            int ret = avcodec_send_packet(codecContext, &packet);
            if (ret < 0) {
                qDebug() << "Error sending a packet for decoding";
                continue;
            }

            AVFrame* frame = av_frame_alloc();
            while (ret >= 0) {
                ret = avcodec_receive_frame(codecContext, frame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    break;
                } else if (ret < 0) {
                    qDebug() << "Error during decoding";
                    break;
                }

                // 转换图像格式并发出信号
                AVFrame* rgbFrame = av_frame_alloc();
                rgbFrame->format = AV_PIX_FMT_RGB24;
                rgbFrame->width = codecContext->width;
                rgbFrame->height = codecContext->height;

                // 分配内存
                int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1);
                uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
                av_image_fill_arrays(
                    rgbFrame->data,
                    rgbFrame->linesize,
                    buffer,
                    AV_PIX_FMT_RGB24,
                    codecContext->width,
                    codecContext->height,
                    1
                );

                // 进行格式转换
                sws_scale(
                    swsContext,
                    (const uint8_t * const *)frame->data,
                    frame->linesize,
                    0,
                    codecContext->height,
                    rgbFrame->data,
                    rgbFrame->linesize
                );

                // 发出信号，通知有帧被解码
                emit frameReady(rgbFrame);

                // 释放内存
                av_freep(&buffer);
                av_frame_free(&rgbFrame);
            }
            av_frame_free(&frame);
        }
        av_packet_unref(&packet);
    }
}

//添加一个函数来启动解码器
void Rtsp_Decoder::startDecoding(){
     // 创建并启动子线程
    decodingThread = new QThread();
    connect(decodingThread, &QThread::started, this, &Rtsp_Decoder::decode);
    connect(this, &Rtsp_Decoder::frameReady, this, &Rtsp_Decoder::onFrameReady, Qt::DirectConnection);
    moveToThread(decodingThread);
    decodingThread->start();
}

void Rtsp_Decoder::stopDecoding(){
    // 请求线程中断
    decodingThread->requestInterruption();
    decodingThread->quit();
    decodingThread->wait();
    delete decodingThread;
    decodingThread = nullptr;
}

void Rtsp_Decoder::onFrameReady(AVFrame* frame){
    // 转换 AVFrame 到 QImage
    QImage image = avframeToQImage(frame);
    emit frameReady(image); // 发送 QImage 信号
}

QImage Rtsp_Decoder::avframeToQImage(const AVFrame *frame)
{
    // 检查帧是否有效
    if (!frame || !frame->data[0])
        return QImage();

    // 获取帧的宽度和高度
    int width = frame->width;
    int height = frame->height;

    // 根据像素格式确定转换上下文
    SwsContext* conversion = sws_getContext(
        width, height, (AVPixelFormat)frame->format,
        width, height, AV_PIX_FMT_RGB24,
        SWS_BILINEAR, nullptr, nullptr, nullptr);

    if (!conversion)
        return QImage();

    // 分配内存以存储转换后的像素数据
    uint8_t* outBuffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, width, height, 1));
    uint8_t* outData[4] = { nullptr };
    int outLinesize[4];

    // 填充outData和outLinesize数组
    av_image_fill_arrays(outData, outLinesize, outBuffer, AV_PIX_FMT_RGB24, width, height, 1);

    // 执行转换
    sws_scale(conversion, frame->data, frame->linesize, 0, height, outData, outLinesize);

    // 创建QImage
    QImage image(outBuffer, width, height, outLinesize[0], QImage::Format_RGB888);

    // 释放资源
    sws_freeContext(conversion);
    av_freep(&outBuffer);

    return image;
}

